Advent of Code 2020: Day 2

Part of the series Advent of Code 2020 (0 posts total).

Advent of Code 2020 Day 2 is special because it is the shortest code I’ve written for any challenge this year. In the challenge you receive a list of passwords and a policy which indicates the lowest and highest amount of times, a single character may be present. Consider the following policies:

1-3 a: abcde
1-3 b: cdefg
2-9 c: ccccccccc

These indicate that password a abcde must contain $a$ between 1 and 3 times inclusive. Since $a$ is only present once, the password is valid. In the second password, however, $b$ is not present at all even though it must be present between 1 and 3 times. Therefore password 2 is invalid. Password 3 is also valid as it contains exactly 9 $c$’s. In my challenge I do not only have three passwords and policies, I have $1000$. Using the power of Regular Expressions (regex) I am able to separate each password into an lower (limit), upper (limit), char (character) and pw (password) variable. For each line I just simply add 1 if the char appears between lower and upper in the pw. All of this is done neatly using Python list shorthand.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import re
# Regular Expression matching each variable in the input
parser = re.compile(r"(\d+)-(\d+) (\w): (\w+)")

with open("input/day02.txt") as file:
    database = parser.findall(file.read())


def part1():
    return sum([1 for lower, upper, char, pw in database
                if int(lower) <= pw.count(char) <= int(upper)])

In part 2, the policy meaning has changed. The range now determines specific characters in the password and at these characters, the char must only appear once. For example, the first password from before now states that character 1 (“a”) and character 3 (“c”) must contain one (1) “a”. Not more or less. Password 1 is still valid. Password 2 is still invalid. Password 3, however, is now invalid as it contains a “c” at both character 2 and 9. This operator of “exactly one, not less not more” is also known as “exclusive or” or “XOR” within programming and electronics. Python has a logical XOR operator, and this is used with the procedure before to produce the answer for part 2

1
2
3
4
def part2():
    return sum([1 for first, second, char, pw in database
                if (pw[int(first) - 1] == char) ^  # XOR
                (pw[int(second) - 1] == char)])

Giving the total code seen below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import re
parser = re.compile(r"(\d+)-(\d+) (\w): (\w+)")

with open("input/day02.txt") as file:
    database = parser.findall(file.read())


def part1():
    return sum([1 for lower, upper, char, pw in database
                if int(lower) <= pw.count(char) <= int(upper)])


def part2():
    return sum([1 for first, second, char, pw in database
                if (pw[int(first) - 1] == char) ^  # XOR
                (pw[int(second) - 1] == char)])


# Printing results
print("Answer to AoC day 2 part 1 is: {}".format(part1()))
print("Answer to AoC day 2 part 2 is: {}".format(part2()))

I have minified this a bit so you can get an idea of how small it really is.

1
2
3
4
import re
d=re.findall(r"(\d+)-(\d+) (\w): (\w+)",open("input/day02.txt").read())
print(sum([1 for l,u,c,p in d if int(l)<=p.count(c)<=int(u)]))
print(sum([1 for f,s,c,p in d if (p[int(f)-1]==c)^(p[int(s)-1]==c)]))

This provides the same result in exactly 211 characters. If I didn’t want to print the results, I could’ve (almost) made this a one-liner, but that isn’t that impressive. I would still have to import the regex library though.


The full code for this day can be found here. The entire repository is available at GitHub.

Published 26. August 2022

Last modified 29. August 2022